/////////////////////////////////////////////////////////////////////////////
	

/////////////////////////////////////////////////////////////////////////////
#include "Level.h"
#include "CSGD_TextureManager.h"
#include "CSGD_Direct3D.h"
#include "Event.h"
#include "EventManager.h"
#include "EntityManager.h"
#include "ParticleManager.h"
#include "LevelManager.h"

#include <Windows.h>
#include <cassert>

#define RANGE 5

/////////////////////////////////////////////////////////////////////////////
// Function		: Default Constructor
// Notes		: Provides default values to variables
/////////////////////////////////////////////////////////////////////////////
CLevel::CLevel(){
	m_szName = NULL;
	m_cPath1 = nullptr;
	m_cPath2 = nullptr;
	m_cPath3 = nullptr;

	m_cTeam1 = nullptr;
	m_cTeam2 = nullptr;
	m_pBoss = nullptr;

	m_bBossLevel = false;
	for (int i = 0; i < 5; i++)
	{
		m_LevelP1[i] = 1.0f;
		m_LevelP2[i] = 1.0f;
	}

}
/////////////////////////////////////////////////////////////////////////////
// Function		: Destructor
// Notes		: Cleans up any dynamically allocated memory
/////////////////////////////////////////////////////////////////////////////
CLevel::~CLevel(){
	delete m_cPath1;
	m_cPath1 = nullptr;
	delete m_cPath2;
	m_cPath2 = nullptr;
	delete m_cPath3;
	m_cPath3 = nullptr;

	if( m_sField.m_nBackgroundImgID != -1 )
		CSGD_TextureManager::GetInstance()->UnloadTexture( m_sField.m_nBackgroundImgID );
	if( m_sField.m_nFieldImgID != -1 )
		CSGD_TextureManager::GetInstance()->UnloadTexture( m_sField.m_nFieldImgID );
	m_sField.m_nBackgroundImgID = -1;
	m_sField.m_nFieldImgID = -1;
}
/////////////////////////////////////////////////////////////////////////////
// Function		: Enter
// Notes		: Sets up teams and their data when a level is entered
/////////////////////////////////////////////////////////////////////////////
void CLevel::Enter( void )
{
	m_cTeam1 = new CTeam(true);
	m_cTeam1->SetTeamID( 1 );

	if( m_bBossLevel == false)
	{
		m_cTeam2 = new CTeam(false);
		m_cTeam2->SetTeamID( 2 );
	}
	else
	{
		m_pBoss = new CBoss;
		CEntityManager::GetInstance()->AddEntity( m_pBoss );
	}
}
/////////////////////////////////////////////////////////////////////////////
// Function		: Exit
// Notes		: Deletes all team data so that the level can be re-entered
/////////////////////////////////////////////////////////////////////////////
void CLevel::Exit( void )
{
	delete m_cTeam1;
	m_cTeam1 = nullptr;

	if( m_bBossLevel == false)
	{
		delete m_cTeam2;
		m_cTeam2 = nullptr;
	}
}
/////////////////////////////////////////////////////////////////////////////
// Function		: Update
// Notes		: Updates every teams units
/////////////////////////////////////////////////////////////////////////////
void CLevel::Update( float fDT ){
	// Check waypoints
	CheckWaypoints();

	// Update team stuff
	/*m_cTeam1->Update( fDT );
	m_cTeam2->Update( fDT );*/
	CParticleManager::GetInstance()->UpdateAll(fDT);
	CEntityManager::GetInstance()->Update( fDT );

}
/////////////////////////////////////////////////////////////////////////////
// Function		: Render
// Notes		: Draws m_sFields images at the specified sizes and each teams renders
/////////////////////////////////////////////////////////////////////////////
void CLevel::Render( void ){

	// if img is allocated, draw at 0,0
	// Assert that the image is valid
	assert( m_sField.m_nFieldImgID != -1 && "CLevel::Render - field image was not set" );

	RECT rect;
	SetRect(&rect, 0, 0, m_sField.m_nWidth, m_sField.m_nFieldHeight);
	CSGD_TextureManager::GetInstance()->Draw( m_sField.m_nFieldImgID, 0, m_sField.m_nHeight - m_sField.m_nFieldHeight, 1.0f, 1.0f, &rect );

	if( m_sField.m_nBackgroundImgID != -1 )
	{
		assert( m_sField.m_nFieldImgID != -1 && "CLevel::Render - background image was not set" );
		SetRect(&rect, 0, 0, m_sField.m_nWidth, m_sField.m_nBgHeight);
		CSGD_TextureManager::GetInstance()->Draw( m_sField.m_nBackgroundImgID, 0, 0, 1.0f, 1.0f, &rect );
	}


	// Draw everything else
	//m_cTeam1->Render();
	//m_cTeam2->Render();
	CParticleManager::GetInstance()->RenderAll();
	CEntityManager::GetInstance()->Render();
}
/////////////////////////////////////////////////////////////////////////////
// Function		: Check Waypoints
// Notes		: Checks if any unit needs a new waypoint
/////////////////////////////////////////////////////////////////////////////
void CLevel::CheckWaypoints( void )
{
	// Check waypoints for Team 1
	CheckLaneWaypoints( m_cTeam1 );

	// Check waypoints for Team 2
	if( m_bBossLevel == false )
		CheckLaneWaypoints( m_cTeam2 );
}
/////////////////////////////////////////////////////////////////////////////
// Function		: Check Lane Waypoints
// Parameters	: team - The team to check
// Notes		: Checks waypoints for each lane
/////////////////////////////////////////////////////////////////////////////
void CLevel::CheckLaneWaypoints( CTeam* team )
{
	// Loop through units in lane 1
	for( unsigned int i = 0; i < team->GetPath1Units().size(); ++i )
	{
		// loop through waypoints in that lane
		for( unsigned int j = 0; j < m_cPath1->GetWaypoints().size(); ++j )
		{
			// Checks if the unit is close to the waypoint
			if( IsClose( team->GetPath1Units()[i]->GetPosX(), team->GetPath1Units()[i]->GetPosY(),
				m_cPath1->GetWaypoints()[j]->GetPos().m_nPosX, m_cPath1->GetWaypoints()[j]->GetPos().m_nPosY ) )
			{
				// Send event for that lane with specific unit as destination and waypoint as sender
				CWaypoint* next = m_cPath1->GetWaypoints()[j];
				if(team->GetPath1Units()[i]->GetTeam() == 1 && j+1 < m_cPath1->GetWaypoints().size() )
					next = m_cPath1->GetWaypoints()[j+1];
				else if(team->GetPath1Units()[i]->GetTeam() == 2 && j > 0)
					next = m_cPath1->GetWaypoints()[j-1];
				CEventManager::GetInstance()->SendEvent( "NEW_WAYPOINT1", next,
					team->GetPath1Units()[i], nullptr );
			}
		}
	}


	// Loop through units in lane 2
	for( unsigned int i = 0; i < team->GetPath2Units().size(); ++i )
	{
		// loop through waypoints in that lane
		for( unsigned int j = 0; j < m_cPath2->GetWaypoints().size(); ++j )
		{
			// Checks if the unit is close to the waypoint
			if( IsClose( team->GetPath2Units()[i]->GetPosX(), team->GetPath2Units()[i]->GetPosY(),
				m_cPath2->GetWaypoints()[j]->GetPos().m_nPosX, m_cPath2->GetWaypoints()[j]->GetPos().m_nPosY ) )
			{
				// Send event for that lane with specific unit as destination and waypoint as sender
				/*unsigned int* k = new unsigned int;
				*k = j;*/
				CWaypoint* next = m_cPath2->GetWaypoints()[j];
				if(team->GetPath2Units()[i]->GetTeam() == 1 && j+1 < m_cPath2->GetWaypoints().size() )
					next = m_cPath2->GetWaypoints()[j+1];
				else if(team->GetPath2Units()[i]->GetTeam() == 2 && j > 0)
					next = m_cPath2->GetWaypoints()[j-1];
				CEventManager::GetInstance()->SendEvent( "NEW_WAYPOINT2", next,
					team->GetPath2Units()[i], nullptr );
			}
		}
	}


	// Loop through units in lane 3
	for( unsigned int i = 0; i < team->GetPath3Units().size(); ++i )
	{
		// loop through waypoints in that lane
		for( unsigned int j = 0; j < m_cPath3->GetWaypoints().size(); ++j )
		{
			// Checks if the unit is close to the waypoint
			if( IsClose( team->GetPath3Units()[i]->GetPosX(), team->GetPath3Units()[i]->GetPosY(),
				m_cPath3->GetWaypoints()[j]->GetPos().m_nPosX, m_cPath3->GetWaypoints()[j]->GetPos().m_nPosY ) )
			{
				// Send event for that lane with specific unit as destination and waypoint as sender
				CWaypoint* next = m_cPath3->GetWaypoints()[j];
				if(team->GetPath3Units()[i]->GetTeam() == 1 && (j+1 < m_cPath3->GetWaypoints().size()) )
					next = m_cPath3->GetWaypoints()[j+1];
				else if(team->GetPath3Units()[i]->GetTeam() == 2 && (j > 0) )
					next = m_cPath3->GetWaypoints()[j-1];
				CEventManager::GetInstance()->SendEvent( "NEW_WAYPOINT3", next,
					team->GetPath3Units()[i], nullptr );
			}
		}
	}
}
/////////////////////////////////////////////////////////////////////////////
// Function		: Is Close
// Notes		: Checks if any unit needs a new waypoint
/////////////////////////////////////////////////////////////////////////////
bool CLevel::IsClose( const float Pos1X, const float Pos1Y, const float Pos2X, const float Pos2Y ){
	if( Pos1X > Pos2X - RANGE && Pos1X < Pos2X + RANGE )
	{
		if( Pos1Y > Pos2Y - RANGE && Pos1Y < Pos2Y + RANGE )
		{
			return true;
		}
		return false;
	}
	return false;
}
